package com.xuecheng.media.service.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.vod.model.v20170321.GetPlayInfoResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.TeachplanMediaDTO;
import com.xuecheng.api.learning.model.vo.ResourceUrlModel;
import com.xuecheng.api.media.model.dto.MediaDTO;
import com.xuecheng.api.media.model.qo.QueryMediaModel;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.AuditEnum;
import com.xuecheng.common.enums.common.ResourceTypeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.media.agent.ContentApiAgent;
import com.xuecheng.media.common.constant.MediaErrorCode;
import com.xuecheng.media.common.utils.AliyunVODUtil;
import com.xuecheng.media.controller.MediaAuditController;
import com.xuecheng.media.controller.MediaController;
import com.xuecheng.media.convert.MediaConvert;
import com.xuecheng.media.entity.Media;
import com.xuecheng.media.mapper.MediaMapper;
import com.xuecheng.media.service.MediaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 媒资信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class MediaServiceImpl extends ServiceImpl<MediaMapper, Media> implements MediaService {



    /*
    * 业务分析：
    *   1.判断关键
    *       companyid  filename  fileid(videoId)
    *   2.给信息数据赋值默认值
    *       auditStatus：未审核
    *
    *   3.保存信息
    *   4.将数据库最新数据返回
    *
    * */
    @Override
    @Transactional
    public MediaDTO createMedia(MediaDTO dto) {

        //1.判断关键
        //     companyid  filename  fileid(videoId)
        if (ObjectUtils.isEmpty(dto.getCompanyId())||
                StringUtil.isBlank(dto.getFilename())||
                StringUtil.isBlank(dto.getFileId())
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }


        // 2.给信息数据赋值默认值
        //     auditStatus：未审核
        dto.setAuditStatus(AuditEnum.AUDIT_UNPAST_STATUS.getCode());



        // 3.保存信息
        Media media = MediaConvert.INSTANCE.dto2entity(dto);
        boolean result = this.save(media);

        if (!result) {
            ExceptionCast.cast(MediaErrorCode.E_140001);
        }

        // 4.将数据库最新数据返回
        Media po = this.getById(media.getId());
        MediaDTO resultDTO = MediaConvert.INSTANCE.entity2dto(po);

        return resultDTO;
    }

    @Override
    public PageVO queryMediaList(PageRequestParams params, QueryMediaModel model, Long companyId) {
        // 1.判断关键数据
        // 分页数据的合法性
        if (params.getPageNo() < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }

        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }


        // 2.构建分页对象
        Page<Media> basePage = new Page<>(params.getPageNo(),params.getPageSize());

        // 3.构建查询条件对象
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();

        // 课程名称     like   完整版
        // 课程审核状态  eq
        // String courseName = model.getCourseName();
        // if (StringUtil.isNotBlank(courseName)) {
        //     queryWrapper.like(CourseBase::getName, courseName);
        // }
        //
        // String auditStatus = model.getAuditStatus();
        // if (StringUtil.isNotBlank(auditStatus)) {
        //     queryWrapper.eq(CourseBase::getAuditStatus, auditStatus);
        // }

        // 简写版
        queryWrapper.like(StringUtil.isNotBlank(model.getFilename()),Media::getFilename, model.getFilename());
        queryWrapper.eq(StringUtil.isNotBlank(model.getType()),Media::getType, model.getType());
        queryWrapper.eq(StringUtil.isNotBlank(model.getAuditStatus()),Media::getAuditStatus, model.getAuditStatus());
        //教学机构只能查询本机构的课程信息
        if (!(ObjectUtils.nullSafeEquals(companyId, MediaAuditController.OPERATION_FLAG))) {
            queryWrapper.eq(Media::getCompanyId, companyId);
        }



        // 4.查询数据内容获得结果
        Page<Media> page = this.page(basePage, queryWrapper);

        List<Media> records = page.getRecords();
        long total = page.getTotal();


        List<MediaDTO> dtos = Collections.emptyList();

        if (!(CollectionUtils.isEmpty(records))) {
            dtos = MediaConvert.INSTANCE.entitys2dtos(records);
        }

        // 5.构建返回结果数据-PageVo
        PageVO pageVO = new PageVO(dtos,total,params.getPageNo(),params.getPageSize());

        return pageVO;
    }

    /*
    * 业务分析：
    *   1.判断关键数据
    *       mediaId
    *   2.判断业务数据
    *       媒资
    *   3.将结果内容返回-使用Restresponse来封装
    *       不管是有还是没有都要返回结果
    * */
    @Override
    public RestResponse<MediaDTO> getMediaById4s(Long mediaId) {

        //1.判断关键数据
        //     mediaId
        if (ObjectUtils.isEmpty(mediaId)) {
            return RestResponse.validfail(CommonErrorCode.E_100101);
        }


        // 2.判断业务数据
        //     媒资
        Media media = this.getById(mediaId);

        if (ObjectUtils.isEmpty(media)) {
            return RestResponse.validfail(MediaErrorCode.E_140005);
        }


        // 3.将结果内容返回-使用Restresponse来封装
        //     不管是有还是没有都要返回结果
        MediaDTO mediaDTO = MediaConvert.INSTANCE.entity2dto(media);
        RestResponse<MediaDTO> response = RestResponse.success(mediaDTO);
        return response;
    }



    @Autowired
    private ContentApiAgent contentApiAgent;

    @Value("${aliyun.region}")
    private  String region;
    @Value("${aliyun.accessKeyId}")
    private  String accessKeyId;
    @Value("${aliyun.accessKeySecret}")
    private  String accessKeySecret;


    @Override
    @Transactional
    public void removeMedia(Long mediaId, Long companyId) {

        // 1.判断关键数据
        if (ObjectUtils.isEmpty(mediaId)||
                ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        // 2.判断业务数据
        // 媒资信息是否存在
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Media::getCompanyId, companyId);
        queryWrapper.eq(Media::getId, mediaId);

        Media media = this.getOne(queryWrapper);

        if (ObjectUtils.isEmpty(media) ) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }

        // 判断媒资是否有关联关系
        RestResponse<List<TeachplanMediaDTO>> restResponse = contentApiAgent.getByMediaId4s(mediaId);

        if (!(restResponse.isSuccessful())) {
            ExceptionCast.castWithCodeAndDesc(restResponse.getCode(),restResponse.getMsg());
        }

        List<TeachplanMediaDTO> result = restResponse.getResult();

        if (!(CollectionUtils.isEmpty(result))) {
            ExceptionCast.cast(MediaErrorCode.E_140003);
        }

        // 3.删除信息
        // 删除阿里云视频信息
        try {
            DefaultAcsClient client = AliyunVODUtil.initVodClient(region, accessKeyId, accessKeySecret);

            String fileId = media.getFileId();
            AliyunVODUtil.deleteVideo(client,fileId);

        } catch (Exception e) {
            log.error(MediaErrorCode.E_140016.getDesc()+" : {}",e.getMessage());
            ExceptionCast.cast(MediaErrorCode.E_140016);
        }

        // 4.将本地media信息删除
        boolean removeResult = this.removeById(mediaId);

        if (!removeResult) {
            ExceptionCast.cast(MediaErrorCode.E_140002);
        }

    }



    @Override
    @Transactional
    public void approveMedia(MediaDTO dto) {

        // 1.判断关键数据
        if (StringUtil.isBlank(dto.getAuditMind())||
                StringUtil.isBlank(dto.getAuditStatus())||
                ObjectUtils.isEmpty(dto.getId())
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        // 2.判断媒资信息
        //     判断是否存在
        //     判断是否是未审核状态
        Media media = this.getById(dto.getId());

        if (ObjectUtils.isEmpty(media)) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }

        String auditStatus = media.getAuditStatus();
        if (!(AuditEnum.AUDIT_UNPAST_STATUS.getCode().equals(auditStatus))) {
            ExceptionCast.cast(MediaErrorCode.E_140017);
        }

        // 判断运营的审核状态是否合法
        String auditStatusOpera = dto.getAuditStatus();
        if (AuditEnum.AUDIT_UNPAST_STATUS.getCode().equals(auditStatusOpera)) {
            ExceptionCast.cast(MediaErrorCode.E_140019);
        }

        // 3.修改媒资信息的审核状态
        LambdaUpdateWrapper<Media> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Media::getAuditStatus, dto.getAuditStatus());
        updateWrapper.set(Media::getChangeDate, LocalDateTime.now());
        updateWrapper.eq(Media::getId, media.getId());

        boolean result = this.update(updateWrapper);
        if (!result) {
            ExceptionCast.cast(MediaErrorCode.E_140001);
        }

    }


    @Override
    public String getPlayUrlByMediaId(Long mediaId, Long companyId) {

        // 1.判断关键数据
        if (ObjectUtils.isEmpty(mediaId)||
                ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        // 2.判断业务数据
        // 媒资信息是否存在
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Media::getId, mediaId);

        if (!(ObjectUtils.nullSafeEquals(companyId, MediaAuditController.OPERATION_FLAG))) {
            queryWrapper.eq(Media::getCompanyId, companyId);
        }

        Media media = this.getOne(queryWrapper);

        if (ObjectUtils.isEmpty(media)) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }

        // 3.获得媒资文件的资源路径地址
        // 判断媒资类型是否是视频类型，如果是需要获得aliyun视频的地址
        String type = media.getType();


        String resourceUrl = null;

        if (ResourceTypeEnum.VIDEO. getCode().equals(type)) {
            resourceUrl = getAliyunVodPlayUrl(media.getFileId());
        } else if (ResourceTypeEnum.DOCUMENT.getCode().equals(type)){
            //获得的媒资文档的资源访问地址路径
        } else if (ResourceTypeEnum.WORK.getCode().equals(type)){
            //获得的媒资文档的资源访问地址路径
        }


        return resourceUrl;
    }

    /**
     * 获得阿里云视频播放地址
     * @param fileId
     * @return
     */
    private String getAliyunVodPlayUrl(String fileId) {

        String playURL = null;
        try {
            DefaultAcsClient client = AliyunVODUtil.initVodClient(region, accessKeyId, accessKeySecret);

            GetPlayInfoResponse playInfo = AliyunVODUtil.getPlayInfo(client, fileId);

            List<GetPlayInfoResponse.PlayInfo> playInfoList = playInfo.getPlayInfoList();

            if (CollectionUtils.isEmpty(playInfoList)) {
                ExceptionCast.cast(MediaErrorCode.E_140018);
            }

            // 默认获得第一个播放地址
            playURL = playInfoList.get(0).getPlayURL();
        } catch (Exception e) {
            log.error(MediaErrorCode.E_140012.getDesc()+" : {}",e.getMessage());
            ExceptionCast.cast(MediaErrorCode.E_140012);
        }

        return playURL;
    }


    /*
     * 业务分析：
     *   1.判断关键数据
     *       mediaId
     *   2.判断业务数据
     *       Media
     *           判断是否存在
     *   3.获得媒资的资源地址数据
     *       判断媒资的类型
     *           如果是视频
     *               从阿里云中后的视频播放地址（点播）--根据fileId：videoid
     *           如果是其他资源
     *               需要从其他资源服务中获得地址
     *   4.封装成结果数据并返回
     *
     * */
    public RestResponse<ResourceUrlModel> getMediaUrl(Long mediaId) {

        //1.判断关键数据
        //     mediaId
        if (ObjectUtils.isEmpty(mediaId)) {
            return RestResponse.validfail(CommonErrorCode.E_100101);
        }

        // 2.判断业务数据
        //     Media
        //         判断是否存在
        Media media = this.getById(mediaId);

        if (ObjectUtils.isEmpty(media)) {
            return RestResponse.validfail(MediaErrorCode.E_140005);
        }


        // 3.获得媒资的资源地址数据
        //     判断媒资的类型
        String type = media.getType();
        if (ResourceTypeEnum.VIDEO.getCode().equals(type)) {
            //         如果是视频
            //             从阿里云中后的视频播放地址（点播）--根据fileId：videoid
            String videoId = media.getFileId();

            String playURL = null;
            try {
                playURL = getAliyunMediaPlayURL(videoId);
            } catch (Exception e) {
                return RestResponse.validfail(e.getMessage());
            }

            ResourceUrlModel urlModel = new ResourceUrlModel();

            urlModel.setPlayUrl(playURL);

            return RestResponse.success(urlModel);


        } else if(ResourceTypeEnum.WORK.getCode().equals(type)){
            //         如果是其他资源
            //             需要从其他资源服务中获得地址
        }

        return null;
    }


    private String getAliyunMediaPlayURL(String videoId) {
        try {
            // 从阿里云视频点播中获得播放地址
            DefaultAcsClient client = AliyunVODUtil.initVodClient(region, accessKeyId, accessKeySecret);

            GetPlayInfoResponse response = AliyunVODUtil.getPlayInfo(client, videoId);

            List<GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList();

            // 默认预览操作获得第一个播放地址
            GetPlayInfoResponse.PlayInfo playInfo = playInfoList.get(0);

            return playInfo.getPlayURL();
        } catch (Exception e) {
            log.error(MediaErrorCode.E_140012.getDesc()+" {}",e.getMessage());
            ExceptionCast.cast(MediaErrorCode.E_140012);
            return null;
        }
    }
}
